package p41_autoconfig;

import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.util.List;

/**
 * 自动配置的经典实现，aop的自动装配
 */
@Configuration
@Import(_2_AopAutoConfig.MyDeferredImportSelector.class)
public class _2_AopAutoConfig {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        StandardEnvironment env = new StandardEnvironment();
        env.getPropertySources().addLast(new SimpleCommandLinePropertySource("--spring.aop.auto=true"));
        context.setEnvironment(env);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.registerBean(_2_AopAutoConfig.class);
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

     static class MyDeferredImportSelector implements DeferredImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            /**
             * AopAutoConfiguration全类名是写在spring.factories文件里，这里为了简单直接得到了
             * AopAutoConfiguration会添加四个bean
             * 阅读AopAutoConfiguration配置类代码的一些知识点:
             * @Configuration注解表示的类默认是基于CGLIB 动态代理的，以便每次调用@Bean方法都会单例bean
             * @Configuration(proxyBeanMethods = false)表示将当前配置类作为一个普通类对待，那么每次调用@Bean方法都会返回新实例
             * AopAutoConfiguration里面的配置类都用到了@Configuration(proxyBeanMethods = false)，是因为此时aop还没有生效，不能基于代理创建配置类
             * @EnableAspectJAutoProxy本质就是@Import
             * ImportBeanDefinitionRegistrar接口的实现类表示可以使用编程方式来创建BeanDefinition对象
             */
            return new String[]{AopAutoConfiguration.class.getName()};
        }
    }
}
